﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Область СлужебныйПрограммныйИнтерфейс

////////////////////////////////////////////////////////////////////////////////
// Обработчики событий подсистем конфигурации.

// См. ОбщегоНазначенияПереопределяемый.ПриДобавленииПараметровРаботыКлиента.
Процедура ПриДобавленииПараметровРаботыКлиента(Параметры) Экспорт
	
	Параметры.Вставить("НастройкиПроксиСервера", ПолучениеФайловИзИнтернета.НастройкиПроксиНаКлиенте());
	
КонецПроцедуры

// См. РаботаВБезопасномРежимеПереопределяемый.ПриВключенииИспользованияПрофилейБезопасности.
Процедура ПриВключенииИспользованияПрофилейБезопасности() Экспорт
	
	// Сброс настроек прокси-сервера на системные.
	СохранитьНастройкиПроксиНаСервере1СПредприятие(Неопределено);
	
	ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации(),
		УровеньЖурналаРегистрации.Предупреждение, Метаданные.Константы.НастройкаПроксиСервера,,
		НСтр("ru = 'При включении профилей безопасности настройки прокси-сервера сброшены на системные.'"));
	
КонецПроцедуры

// См. РаботаВБезопасномРежимеПереопределяемый.ПриЗаполненииРазрешенийНаДоступКВнешнимРесурсам.
Процедура ПриЗаполненииРазрешенийНаДоступКВнешнимРесурсам(ЗапросыРазрешений) Экспорт
	
	МодульРаботаВБезопасномРежиме = ОбщегоНазначения.ОбщийМодуль("РаботаВБезопасномРежиме");
	
	Разрешения = Новый Массив();
	
	// Разрешения для выполнения процедур ПолучениеФайловИзИнтернетаСлужебный.ПроверитьДоступностьСервера,
	// ПолучениеФайловИзИнтернетаСлужебный.ЖурналТрассировкиМаршрутаСервера
	Если ОбщегоНазначения.ЭтоWindowsСервер() Тогда
		Разрешения.Добавить(МодульРаботаВБезопасномРежиме.РазрешениеНаИспользованиеПриложенияОперационнойСистемы("cmd /S /C ""%(ping %)%""",
			НСтр("ru = 'Разрешение для ping'", ОбщегоНазначения.КодОсновногоЯзыка())));
		Разрешения.Добавить(МодульРаботаВБезопасномРежиме.РазрешениеНаИспользованиеПриложенияОперационнойСистемы("cmd /S /C ""%(tracert %)%""",
			НСтр("ru = 'Разрешение для tracert.'", ОбщегоНазначения.КодОсновногоЯзыка())));
	ИначеЕсли ОбщегоНазначения.ЭтоLinuxСервер() Тогда
		Разрешения.Добавить(МодульРаботаВБезопасномРежиме.РазрешениеНаИспользованиеПриложенияОперационнойСистемы("ping % % % % %",
			НСтр("ru = 'Разрешение для ping'", ОбщегоНазначения.КодОсновногоЯзыка())));
		Разрешения.Добавить(МодульРаботаВБезопасномРежиме.РазрешениеНаИспользованиеПриложенияОперационнойСистемы("traceroute % % % % %",
			НСтр("ru = 'Разрешение для traceroute.'", ОбщегоНазначения.КодОсновногоЯзыка())));
	КонецЕсли;
	
	ЗапросыРазрешений.Добавить(
		МодульРаботаВБезопасномРежиме.ЗапросНаИспользованиеВнешнихРесурсов(Разрешения));
	
КонецПроцедуры


#КонецОбласти

#Область СлужебныеПроцедурыИФункции

#Область Прокси

// Сохраняет параметры настройки прокси сервера на стороне сервера 1С:Предприятие.
//
Процедура СохранитьНастройкиПроксиНаСервере1СПредприятие(Знач Настройки) Экспорт
	
	Если НЕ Пользователи.ЭтоПолноправныйПользователь(, Истина) Тогда
		ВызватьИсключение(НСтр("ru = 'Недостаточно прав для выполнения операции'"));
	КонецЕсли;
	
	УстановитьПривилегированныйРежим(Истина);
	Константы.НастройкаПроксиСервера.Установить(Новый ХранилищеЗначения(Настройки));
	
КонецПроцедуры

#КонецОбласти

#Область СкачатьФайл

#Если Не ВебКлиент Тогда

// Функция для получения файла из сети Интернет.
//
// Параметры:
//   URL           - Строка - url файла.
//   ПараметрыПолучения   - Структура:
//    * ПутьДляСохранения            - Строка - путь на сервере (включая имя файла), для сохранения скачанного файла.
//    * Пользователь                 - Строка - пользователь от имени которого установлено соединение.
//    * Пароль                       - Строка - пароль пользователя от которого установлено соединение.
//    * Порт                         - Число  - порт сервера с которым установлено соединение.
//    * Таймаут                      - Число  - таймаут на получение файла, в секундах.
//    * ЗащищенноеСоединение         - Булево - для случая http загрузки флаг указывает,
//                                             что соединение должно производиться через https.
//    * ПассивноеСоединение          - Булево - для случая ftp загрузки флаг указывает,
//                                             что соединение должно пассивным (или активным).
//    * Заголовки                    - Соответствие - см. описание параметра Заголовки объекта HTTPЗапрос.
//    * ИспользоватьАутентификациюОС - Булево - см. описание параметра ИспользоватьАутентификациюОС объекта HTTPСоединение.
//
//   НастройкаСохранения - Соответствие - содержит параметры для сохранения скачанного файла. Ключи:
//                 МестоХранения - Строка - может содержать
//                        "Сервер" - сервер,
//                        "ВременноеХранилище" - временное хранилище.
//                 Путь - строка (необязательный параметр) -
//                        путь к каталогу на клиенте либо на сервере либо адрес во временном хранилище
//                        если не задано будет сгенерировано автоматически.
//   ЗаписыватьОшибку - Булево                     
//
// Возвращаемое значение:
//   Структура:
//      * Статус - Булево
//      * Путь   - Строка
//      * СообщениеОбОшибке - Строка
//      * Заголовки         - Соответствие
//      * КодСостояния      - Число
//
Функция СкачатьФайл(Знач URL, Знач ПараметрыПолучения, Знач НастройкаСохранения, Знач ЗаписыватьОшибку = Истина) Экспорт
	
	НастройкиПолучения = ПолучениеФайловИзИнтернетаКлиентСервер.ПараметрыПолученияФайла();
	Если ПараметрыПолучения <> Неопределено Тогда
		ЗаполнитьЗначенияСвойств(НастройкиПолучения, ПараметрыПолучения);
	КонецЕсли;
	
	Если НастройкаСохранения.Получить("МестоХранения") <> "ВременноеХранилище" Тогда
		НастройкаСохранения.Вставить("Путь", НастройкиПолучения.ПутьДляСохранения);
	КонецЕсли;
	
	НастройкаПроксиСервера = ПолучениеФайловИзИнтернета.НастройкиПроксиНаСервере();
	
	Перенаправления = Новый Массив;
	
	Возврат ПолучитьФайлИзИнтернет(URL, НастройкаСохранения, НастройкиПолучения,
		НастройкаПроксиСервера, ЗаписыватьОшибку, Перенаправления);
	
КонецФункции

// Функция для получения файла из сети Интернет.
//
// Параметры:
//   URL - Строка - url файла в формате: [Протокол://]<Сервер>/<Путь к файлу на сервере>.
//
// НастройкаСоединения - Соответствие -
//		ЗащищенноеСоединение* - булево - соединение защищенное.
//		ПассивноеСоединение*  - булево - соединение защищенное.
//		Пользователь - строка - пользователь от имени которого установлено соединение.
//		Пароль       - строка - пароль пользователя от которого установлено соединение.
//		Порт         - число  - порт сервера с которым установлено соединение
//		* - взаимоисключающие ключи.
//
// НастройкиПрокси - Соответствие из КлючИЗначение:
//     * Ключ - Строка
//     * Значение - Произвольный
//    Ключи:
//		# ИспользоватьПрокси - Булево - использовать ли прокси-сервер.
//		# НеИспользоватьПроксиДляЛокальныхАдресов - Булево - использовать ли прокси-сервер для локальных адресов.
//		# ИспользоватьСистемныеНастройки - Булево - использовать ли системные настройки прокси-сервера.
//		# Сервер       - Строка - адрес прокси-сервера.
//		# Порт         - Булево - порт прокси-сервера.
//		# Пользователь - Строка - имя пользователя для авторизации на прокси-сервере.
//		# Пароль       - Строка - пароль пользователя.
//		# ИспользоватьАутентификациюОС - Булево - признак использования аутентификации средствами операционной системы.
//
// НастройкаСохранения - соответствие - содержит параметры для сохранения скачанного файла.
//		МестоХранения - строка - может содержать
//			"Сервер" - сервер,
//			"ВременноеХранилище" - временное хранилище.
//		Путь - строка (необязательный параметр) - путь к каталогу на клиенте либо на сервере,
//			либо адрес во временном хранилище,  если не задано будет сгенерировано автоматически.
//
// Возвращаемое значение:
//   Структура:
//      * Статус - Булево
//      * Путь   - Строка
//      * СообщениеОбОшибке - Строка
//      * Заголовки         - Соответствие
//      * КодСостояния      - Число
//
Функция ПолучитьФайлИзИнтернет(Знач URL, Знач НастройкаСохранения, Знач НастройкаСоединения,
	Знач НастройкиПрокси, Знач ЗаписыватьОшибку, Перенаправления = Неопределено)
	
	СтруктураURI = ОбщегоНазначенияКлиентСервер.СтруктураURI(URL);
	
	Сервер        = СтруктураURI.Хост;
	ПутьНаСервере = СтруктураURI.ПутьНаСервере;
	Протокол      = СтруктураURI.Схема;
	
	Если ПустаяСтрока(Протокол) Тогда 
		Протокол = "http";
	КонецЕсли;
	
	ЗащищенноеСоединение = НастройкаСоединения.ЗащищенноеСоединение;
	ИмяПользователя      = НастройкаСоединения.Пользователь;
	ПарольПользователя   = НастройкаСоединения.Пароль;
	Порт                 = НастройкаСоединения.Порт;
	Таймаут              = НастройкаСоединения.Таймаут;
	
	Если (Протокол = "https" Или Протокол = "ftps") И ЗащищенноеСоединение = Неопределено Тогда
		ЗащищенноеСоединение = Истина;
	КонецЕсли;
	
	Если ЗащищенноеСоединение = Истина Тогда
		ЗащищенноеСоединение = ОбщегоНазначенияКлиентСервер.НовоеЗащищенноеСоединение();
	ИначеЕсли ЗащищенноеСоединение = Ложь Тогда
		ЗащищенноеСоединение = Неопределено;
		// Иначе параметр ЗащищенноеСоединение был задан в явном виде.
	КонецЕсли;
	
	Если Порт = Неопределено Тогда
		Порт = СтруктураURI.Порт;
	КонецЕсли;
	
	Если НастройкиПрокси = Неопределено Тогда 
		Прокси = Неопределено;
	Иначе 
		Прокси = НовыйИнтернетПрокси(НастройкиПрокси, Протокол);
	КонецЕсли;
	
	Если НастройкаСохранения["Путь"] <> Неопределено Тогда
		ПутьДляСохранения = НастройкаСохранения["Путь"];
	Иначе
		ПутьДляСохранения = ПолучитьИмяВременногоФайла(); // АПК:441 Временный файл должен удаляться вызывающим кодом.
	КонецЕсли;
	
	Если Таймаут = Неопределено Тогда 
		Таймаут = ПолучениеФайловИзИнтернетаКлиентСервер.АвтоматическоеОпределениеТаймаута();
	КонецЕсли;
	
	ИспользуетсяFTPПротокол = (Протокол = "ftp" Или Протокол = "ftps");
	
	Если ИспользуетсяFTPПротокол Тогда
		
		ПассивноеСоединение                       = НастройкаСоединения.ПассивноеСоединение;
		УровеньИспользованияЗащищенногоСоединения = НастройкаСоединения.УровеньИспользованияЗащищенногоСоединения;
		
		Попытка
			
			Если Таймаут = ПолучениеФайловИзИнтернетаКлиентСервер.АвтоматическоеОпределениеТаймаута() Тогда
				
				Соединение = Новый FTPСоединение(
					Сервер, 
					Порт, 
					ИмяПользователя, 
					ПарольПользователя,
					Прокси, 
					ПассивноеСоединение, 
					7, 
					ЗащищенноеСоединение, 
					УровеньИспользованияЗащищенногоСоединения);
				
				РазмерФайла = РазмерФайлаFTP(Соединение, ПутьНаСервере);
				Таймаут = ТаймаутПоРазмеруФайла(РазмерФайла);
				
			КонецЕсли;
			
			Соединение = Новый FTPСоединение(
				Сервер, 
				Порт, 
				ИмяПользователя, 
				ПарольПользователя,
				Прокси, 
				ПассивноеСоединение, 
				Таймаут, 
				ЗащищенноеСоединение, 
				УровеньИспользованияЗащищенногоСоединения);
			
			Сервер = Соединение.Сервер;
			Порт   = Соединение.Порт;
			
			Соединение.Получить(ПутьНаСервере, ПутьДляСохранения);
			
		Исключение
			
			РезультатДиагностики = ПолучениеФайловИзИнтернета.ДиагностикаСоединения(URL, ЗаписыватьОшибку);
			
			ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Не удалось получить файл %1 с сервера %2:%3
				           |по причине:
				           |%4
				           |Результат диагностики:
				           |%5'"),
				URL, Сервер, Формат(Порт, "ЧГ="),
				ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()),
				РезультатДиагностики.ОписаниеОшибки);
				
			Если ЗаписыватьОшибку Тогда
				СообщениеОбОшибке = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = '%1
					           |
					           |Трассировка:
					           |Защищенное соединение: %2
					           |Таймаут: %3'"),
					ТекстОшибки,
					Формат(Соединение.ЗащищенноеСоединение, НСтр("ru = 'БЛ=Нет; БИ=Да'")),
					Формат(Соединение.Таймаут, "ЧГ=0"));
					
				ЗаписатьОшибкуВЖурналРегистрации(СообщениеОбОшибке);
			КонецЕсли;
			
			Возврат РезультатПолученияФайла(Ложь, ТекстОшибки);
			
		КонецПопытки;
		
	Иначе // Используется HTTP протокол.
		
		Заголовки                    = НастройкаСоединения.Заголовки;
		ИспользоватьАутентификациюОС = НастройкаСоединения.ИспользоватьАутентификациюОС;
		
		Попытка
			
			Если Таймаут = ПолучениеФайловИзИнтернетаКлиентСервер.АвтоматическоеОпределениеТаймаута() Тогда
				
				Соединение = Новый HTTPСоединение(
					Сервер, 
					Порт, 
					ИмяПользователя, 
					ПарольПользователя,
					Прокси, 
					7, 
					ЗащищенноеСоединение, 
					ИспользоватьАутентификациюОС);
				
				РазмерФайла = РазмерФайлаHTTP(Соединение, ПутьНаСервере, Заголовки);
				Таймаут = ТаймаутПоРазмеруФайла(РазмерФайла);
				
			КонецЕсли;
			
			Соединение = Новый HTTPСоединение(
				Сервер, 
				Порт, 
				ИмяПользователя, 
				ПарольПользователя,
				Прокси, 
				Таймаут, 
				ЗащищенноеСоединение, 
				ИспользоватьАутентификациюОС);
			
			Сервер = Соединение.Сервер;
			Порт   = Соединение.Порт;
			
			ЗапросHTTP = Новый HTTPЗапрос(ПутьНаСервере, Заголовки);
			ЗапросHTTP.Заголовки.Вставить("Accept-Charset", "UTF-8");
			ЗапросHTTP.Заголовки.Вставить("X-1C-Request-UID", Строка(Новый УникальныйИдентификатор));
			ОтветHTTP = Соединение.Получить(ЗапросHTTP, ПутьДляСохранения);
			
		Исключение
			
			РезультатДиагностики = ПолучениеФайловИзИнтернета.ДиагностикаСоединения(URL, ЗаписыватьОшибку);
			
			ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Не удалось установить HTTP-соединение с сервером %1:%2
				           |по причине:
				           |%3
				           |
				           |Результат диагностики:
				           |%4'"),
				Сервер, Формат(Порт, "ЧГ="),
				ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()),
				РезультатДиагностики.ОписаниеОшибки);
			
			ДописатьПредставлениеПеренаправлений(Перенаправления, ТекстОшибки);
			
			Если ЗаписыватьОшибку Тогда
				ЗаписатьОшибкуВЖурналРегистрации(ТекстОшибки);
			КонецЕсли;
				
			Возврат РезультатПолученияФайла(Ложь, ТекстОшибки);
			
		КонецПопытки;
		
		Попытка
			
			Если ОтветHTTP.КодСостояния = 301 // 301 Moved Permanently
				Или ОтветHTTP.КодСостояния = 302 // 302 Found, 302 Moved Temporarily
				Или ОтветHTTP.КодСостояния = 303 // 303 See Other by GET
				Или ОтветHTTP.КодСостояния = 307 // 307 Temporary Redirect
				Или ОтветHTTP.КодСостояния = 308 Тогда // 308 Permanent Redirect
				
				Если Перенаправления.Количество() > 7 Тогда
					ВызватьИсключение 
						НСтр("ru = 'Превышено количество перенаправлений.'");
				Иначе 
					
					НовыйURL = СтандартныеПодсистемыСервер.HTTPЗаголовкиВНижнийРегистр(ОтветHTTP.Заголовки)["location"];
					Если НовыйURL = Неопределено Тогда 
						ВызватьИсключение 
							НСтр("ru = 'Некорректное перенаправление, отсутствует HTTP-заголовок ответа ""Location"".'");
					КонецЕсли;
					
					НовыйURL = СокрЛП(НовыйURL);
					Если ПустаяСтрока(НовыйURL) Тогда
						ВызватьИсключение 
							НСтр("ru = 'Некорректное перенаправление, пустой HTTP-заголовок ответа ""Location"".'");
					КонецЕсли;
					
					Если Перенаправления.Найти(НовыйURL) <> Неопределено Тогда
						ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
							НСтр("ru = 'Циклическое перенаправление.
							           |Попытка перейти на %1 уже выполнялась ранее.'"),
							НовыйURL);
					КонецЕсли;
					
					Перенаправления.Добавить(URL);
					Если Не СтрНачинаетсяС(НовыйURL, "http") Тогда
						// <схема>://<хост>:<порт>/<путь>
						НовыйURL = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
							"%1://%2:%3/%4", Протокол, Сервер, Формат(Порт, "ЧГ="), НовыйURL);
					КонецЕсли;
					
					Возврат ПолучитьФайлИзИнтернет(НовыйURL, НастройкаСохранения, НастройкаСоединения,
						НастройкиПрокси, ЗаписыватьОшибку, Перенаправления);
					
				КонецЕсли;
				
			КонецЕсли;
			
			Если ОтветHTTP.КодСостояния < 200 Или ОтветHTTP.КодСостояния >= 300 Тогда
				
				Если ОтветHTTP.КодСостояния = 304 Тогда
					
					HTTPЗаголовки = СтандартныеПодсистемыСервер.HTTPЗаголовкиВНижнийРегистр(ЗапросHTTP.Заголовки);
					Если (HTTPЗаголовки["if-modified-since"] <> Неопределено Или HTTPЗаголовки["if-none-match"] <> Неопределено) Тогда
						ЗаписыватьОшибку = Ложь;
					КонецЕсли;
					
					ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = 'Сервер убежден, что с вашего последнего запроса его ответ не изменился:
						           |%1'"),
						РасшифровкаКодаСостоянияHTTP(ОтветHTTP.КодСостояния));
					
					ДописатьТелоОтветаСервера(ПутьДляСохранения, ТекстОшибки);
					
					ВызватьИсключение ТекстОшибки;
					
				ИначеЕсли ОтветHTTP.КодСостояния < 200
					Или ОтветHTTP.КодСостояния >= 300 И ОтветHTTP.КодСостояния < 400 Тогда
					
					ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = 'Неподдерживаемый ответ сервера:
						           |%1'"),
						РасшифровкаКодаСостоянияHTTP(ОтветHTTP.КодСостояния));
					
					ДописатьТелоОтветаСервера(ПутьДляСохранения, ТекстОшибки);
					
					ВызватьИсключение ТекстОшибки;
					
				ИначеЕсли ОтветHTTP.КодСостояния >= 400 И ОтветHTTP.КодСостояния < 500 Тогда 
					
					ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = 'Ошибка при выполнении запроса:
						           |%1'"),
						РасшифровкаКодаСостоянияHTTP(ОтветHTTP.КодСостояния));
					
					ДописатьТелоОтветаСервера(ПутьДляСохранения, ТекстОшибки);
					
					ВызватьИсключение ТекстОшибки;
					
				Иначе 
					
					ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = 'Ошибка сервера при обработке запроса к ресурсу:
						           |%1'"),
						РасшифровкаКодаСостоянияHTTP(ОтветHTTP.КодСостояния));
					
					ДописатьТелоОтветаСервера(ПутьДляСохранения, ТекстОшибки);
					
					ВызватьИсключение ТекстОшибки;
					
				КонецЕсли;
				
			КонецЕсли;
			
		Исключение
			
			ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Не удалось получить файл %1 с сервера %2:%3
				           |по причине:
				           |%4'"),
				URL, Сервер, Формат(Порт, "ЧГ="),
				ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
			
			ДописатьПредставлениеПеренаправлений(Перенаправления, ТекстОшибки);
			
			Если ЗаписыватьОшибку Тогда
				СообщениеОбОшибке = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = '%1
					           |
					           |Трассировка:
					           |Защищенное соединение: %2
					           |Таймаут: %3
					           |Аутентификация ОС: %4'"),
					ТекстОшибки,
					Формат(Соединение.ЗащищенноеСоединение, НСтр("ru = 'БЛ=Нет; БИ=Да'")),
					Формат(Соединение.Таймаут, "ЧГ=0"),
					Формат(Соединение.ИспользоватьАутентификациюОС, НСтр("ru = 'БЛ=Нет; БИ=Да'")));
				
				ДописатьЗаголовкиHTTP(ЗапросHTTP, СообщениеОбОшибке);
				ДописатьЗаголовкиHTTP(ОтветHTTP, СообщениеОбОшибке);
				
				ЗаписатьОшибкуВЖурналРегистрации(СообщениеОбОшибке);
			КонецЕсли;
			
			Возврат РезультатПолученияФайла(Ложь, ТекстОшибки, ОтветHTTP);
			
		КонецПопытки;
		
	КонецЕсли;
	
	// Если сохраняем файл в соответствии с настройкой.
	Если НастройкаСохранения["МестоХранения"] = "ВременноеХранилище" Тогда
		КлючУникальности = Новый УникальныйИдентификатор;
		Адрес = ПоместитьВоВременноеХранилище (Новый ДвоичныеДанные(ПутьДляСохранения), КлючУникальности);
		Возврат РезультатПолученияФайла(Истина, Адрес, ОтветHTTP);
	ИначеЕсли НастройкаСохранения["МестоХранения"] = "Сервер" Тогда
		Возврат РезультатПолученияФайла(Истина, ПутьДляСохранения, ОтветHTTP);
	Иначе
		ВызватьИсключение НСтр("ru = 'Не указано место для сохранения файла.'");
	КонецЕсли;
	
КонецФункции

// Параметры:
//   Статус - Булево - успех или неуспех операции.
//   СообщениеПуть - Строка
//   HTTPОтвет - HTTPОтвет
//
// Возвращаемое значение:
//   Структура:
//      * Статус - Булево
//      * Путь   - Строка
//      * СообщениеОбОшибке - Строка
//      * Заголовки         - Соответствие
//      * КодСостояния      - Число
//
Функция РезультатПолученияФайла(Знач Статус, Знач СообщениеПуть, HTTPОтвет = Неопределено)
	
	Результат = Новый Структура("Статус", Статус);
	
	Если Статус Тогда
		Результат.Вставить("Путь", СообщениеПуть);
	Иначе
		Результат.Вставить("СообщениеОбОшибке", СообщениеПуть);
		Результат.Вставить("КодСостояния", 1);
	КонецЕсли;
	
	Если HTTPОтвет <> Неопределено Тогда
		ЗаголовкиОтвета = HTTPОтвет.Заголовки;
		Если ЗаголовкиОтвета <> Неопределено Тогда
			Результат.Вставить("Заголовки", ЗаголовкиОтвета);
		КонецЕсли;
		
		Результат.Вставить("КодСостояния", HTTPОтвет.КодСостояния);
		
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

Функция РазмерФайлаHTTP(СоединениеHTTP, Знач ПутьНаСервере, Знач Заголовки = Неопределено)
	
	ЗапросHTTP = Новый HTTPЗапрос(ПутьНаСервере, Заголовки);
	Попытка
		ПолученныеЗаголовки = СоединениеHTTP.ПолучитьЗаголовки(ЗапросHTTP);// HEAD
	Исключение
		Возврат 0;
	КонецПопытки;
	РазмерСтрокой = СтандартныеПодсистемыСервер.HTTPЗаголовкиВНижнийРегистр(ПолученныеЗаголовки.Заголовки)["content-length"];
	
	ТипЧисло = Новый ОписаниеТипов("Число");
	РазмерФайла = ТипЧисло.ПривестиЗначение(РазмерСтрокой);
	
	Возврат РазмерФайла;
	
КонецФункции

Функция РазмерФайлаFTP(СоединениеFTP, Знач ПутьНаСервере)
	
	РазмерФайла = 0;
	
	Попытка
		НайденныеФайлы = СоединениеFTP.НайтиФайлы(ПутьНаСервере);
		Если НайденныеФайлы.Количество() > 0 Тогда
			РазмерФайла = НайденныеФайлы[0].Размер();
		КонецЕсли;
	Исключение
		РазмерФайла = 0;
	КонецПопытки;
	
	Возврат РазмерФайла;
	
КонецФункции

Функция ТаймаутПоРазмеруФайла(Размер)
	
	БайтВМегабайте = 1048576;
	
	Если Размер > БайтВМегабайте Тогда
		КоличествоСекунд = Окр(Размер / БайтВМегабайте * 128);
		Возврат ?(КоличествоСекунд > 43200, 43200, КоличествоСекунд);
	КонецЕсли;
	
	Возврат 128;
	
КонецФункции

Функция РасшифровкаКодаСостоянияHTTP(КодСостояния)
	
	Если КодСостояния = 304 Тогда // Not Modified
		Расшифровка = НСтр("ru = 'Нет необходимости повторно передавать запрошенные ресурсы.'");
	ИначеЕсли КодСостояния = 400 Тогда // Bad Request
		Расшифровка = НСтр("ru = 'Запрос не может быть исполнен.'");
	ИначеЕсли КодСостояния = 401 Тогда // Unauthorized
		Расшифровка = НСтр("ru = 'Попытка авторизации на сервере была отклонена.'");
	ИначеЕсли КодСостояния = 402 Тогда // Payment Required
		Расшифровка = НСтр("ru = 'Требуется оплата.'");
	ИначеЕсли КодСостояния = 403 Тогда // Forbidden
		Расшифровка = НСтр("ru = 'К запрашиваемому ресурсу нет доступа.'");
	ИначеЕсли КодСостояния = 404 Тогда // Not Found
		Расшифровка = НСтр("ru = 'Запрашиваемый ресурс не существует на сервере.'");
	ИначеЕсли КодСостояния = 405 Тогда // Method Not Allowed
		Расшифровка = НСтр("ru = 'Метод запроса не поддерживается сервером.'");
	ИначеЕсли КодСостояния = 406 Тогда // Not Acceptable
		Расшифровка = НСтр("ru = 'Запрошенный формат данных не поддерживается сервером.'");
	ИначеЕсли КодСостояния = 407 Тогда // Proxy Authentication Required
		Расшифровка = НСтр("ru = 'Ошибка аутентификации на прокси-сервере'");
	ИначеЕсли КодСостояния = 408 Тогда // Request Timeout
		Расшифровка = НСтр("ru = 'Время ожидания сервером передачи от клиента истекло.'");
	ИначеЕсли КодСостояния = 409 Тогда // Conflict
		Расшифровка = НСтр("ru = 'Запрос не может быть выполнен из-за конфликтного обращения к ресурсу.'");
	ИначеЕсли КодСостояния = 410 Тогда // Gone
		Расшифровка = НСтр("ru = 'Ресурс на сервере был перемещен.'");
	ИначеЕсли КодСостояния = 411 Тогда // Length Required
		Расшифровка = НСтр("ru = 'Сервер требует указание ""Content-length."" в заголовке запроса.'");
	ИначеЕсли КодСостояния = 412 Тогда // Precondition Failed
		Расшифровка = НСтр("ru = 'Запрос не применим к ресурсу'");
	ИначеЕсли КодСостояния = 413 Тогда // Request Entity Too Large
		Расшифровка = НСтр("ru = 'Сервер отказывается обработать, слишком большой объем передаваемых данных.'");
	ИначеЕсли КодСостояния = 414 Тогда // Request-URL Too Long
		Расшифровка = НСтр("ru = 'Сервер отказывается обработать, слишком длинный URL.'");
	ИначеЕсли КодСостояния = 415 Тогда // Unsupported Media-Type
		Расшифровка = НСтр("ru = 'Сервер заметил, что часть запроса была сделана в неподдерживаемом формат'");
	ИначеЕсли КодСостояния = 416 Тогда // Requested Range Not Satisfiable
		Расшифровка = НСтр("ru = 'Часть запрашиваемого ресурса не может быть предоставлена'");
	ИначеЕсли КодСостояния = 417 Тогда // Expectation Failed
		Расшифровка = НСтр("ru = 'Сервер не может предоставить ответ на указанный запрос.'");
	ИначеЕсли КодСостояния = 429 Тогда // Too Many Requests
		Расшифровка = НСтр("ru = 'Слишком много запросов за короткое время.'");
	ИначеЕсли КодСостояния = 500 Тогда // Internal Server Error
		Расшифровка = НСтр("ru = 'Внутренняя ошибка интернет-сервера.'");
	ИначеЕсли КодСостояния = 501 Тогда // Not Implemented
		Расшифровка = НСтр("ru = 'Сервер не поддерживает метод запроса.'");
	ИначеЕсли КодСостояния = 502 Тогда // Bad Gateway
		Расшифровка = НСтр("ru = 'Сервер, выступая в роли шлюза или прокси-сервера, 
		                         |получил недействительное ответное сообщение от вышестоящего сервера.'");
	ИначеЕсли КодСостояния = 503 Тогда // Server Unavailable
		Расшифровка = НСтр("ru = 'Сервер временно не доступен.'");
	ИначеЕсли КодСостояния = 504 Тогда // Gateway Timeout
		Расшифровка = НСтр("ru = 'Сервер в роли шлюза или прокси-сервера 
		                         |не дождался ответа от вышестоящего сервера для завершения текущего запроса.'");
	ИначеЕсли КодСостояния = 505 Тогда // HTTP Version Not Supported
		Расшифровка = НСтр("ru = 'Сервер не поддерживает указанную в запросе версию протокола HTTP'");
	ИначеЕсли КодСостояния = 506 Тогда // Variant Also Negotiates
		Расшифровка = НСтр("ru = 'Сервер настроен некорректно, и не способен обработать запрос.'");
	ИначеЕсли КодСостояния = 507 Тогда // Insufficient Storage
		Расшифровка = НСтр("ru = 'На сервере недостаточно места для выполнения запроса.'");
	ИначеЕсли КодСостояния = 509 Тогда // Bandwidth Limit Exceeded
		Расшифровка = НСтр("ru = 'Сервер превысил отведенное ограничение на потребление трафика.'");
	ИначеЕсли КодСостояния = 510 Тогда // Not Extended
		Расшифровка = НСтр("ru = 'Сервер требует больше информации о совершаемом запросе.'");
	ИначеЕсли КодСостояния = 511 Тогда // Network Authentication Required
		Расшифровка = НСтр("ru = 'Требуется авторизация на сервере.'");
	Иначе 
		Расшифровка = НСтр("ru = '<Неизвестный код состояния>.'");
	КонецЕсли;
	
	Возврат СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = '[%1] %2'"), 
		КодСостояния, 
		Расшифровка);
	
КонецФункции

Процедура ДописатьПредставлениеПеренаправлений(Перенаправления, ТекстОшибки)
	
	Если Перенаправления.Количество() > 0 Тогда 
		ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = '%1
			           |
			           |Выполненные перенаправления (%2):
			           |%3'"),
			ТекстОшибки,
			Перенаправления.Количество(),
			СтрСоединить(Перенаправления, Символы.ПС));
	КонецЕсли;
	
КонецПроцедуры

Процедура ДописатьТелоОтветаСервера(ПутьКФайлу, ТекстОшибки)
	
	ТелоОтветаСервера = ТекстИзHTMLИзФайла(ПутьКФайлу);
	
	Если Не ПустаяСтрока(ТелоОтветаСервера) Тогда 
		ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = '%1
			           |
			           |Сообщение, полученное от сервера:
			           |%2'"),
			ТекстОшибки,
			ТелоОтветаСервера);
	КонецЕсли;
	
КонецПроцедуры

Функция ТекстИзHTMLИзФайла(ПутьКФайлу)
	
	ФайлОтвета = Новый ЧтениеТекста(ПутьКФайлу, КодировкаТекста.UTF8);
	ИсходныйТекст = ФайлОтвета.Прочитать(1024 * 15);
	ТекстОшибки = СтроковыеФункцииКлиентСервер.ИзвлечьТекстИзHTML(ИсходныйТекст);
	ФайлОтвета.Закрыть();
	
	Возврат ТекстОшибки;
	
КонецФункции

Процедура ДописатьЗаголовкиHTTP(Объект, ТекстОшибки)
	
	Если ТипЗнч(Объект) = Тип("HTTPЗапрос") Тогда 
		ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = '%1
			           |
			           |HTTP запрос:
			           |Адрес ресурса: %2
			           |Заголовки: %3'"),
			ТекстОшибки,
			Объект.АдресРесурса,
			ПредставлениеЗаголовковHTTP(Объект.Заголовки));
	ИначеЕсли ТипЗнч(Объект) = Тип("HTTPОтвет") Тогда
		ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = '%1
			           |
			           |HTTP ответ:
			           |Код ответа: %2
			           |Заголовки: %3'"),
			ТекстОшибки,
			Объект.КодСостояния,
			ПредставлениеЗаголовковHTTP(Объект.Заголовки));
	КонецЕсли;
	
КонецПроцедуры

Функция ПредставлениеЗаголовковHTTP(Заголовки)
	
	ПредставлениеЗаголовков = "";
	
	Для каждого Заголовок Из Заголовки Цикл 
		ПредставлениеЗаголовков = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = '%1
			           |%2: %3'"), 
			ПредставлениеЗаголовков,
			Заголовок.Ключ, Заголовок.Значение);
	КонецЦикла;
		
	Возврат ПредставлениеЗаголовков;
	
КонецФункции

Функция ПредставлениеИнтернетПрокси(Прокси, Протокол = Неопределено)
	
	Журнал = Новый Массив;
	Если ЗначениеЗаполнено(Протокол) Тогда
		Сервер = Прокси.Сервер(Протокол);
		Порт = Прокси.Порт(Протокол);
		
		Если ЗначениеЗаполнено(Сервер) Тогда
			Если Не ЗначениеЗаполнено(Порт) Тогда
				Порт = ПортПоУмолчанию(Протокол);
			КонецЕсли;
		Иначе
			Сервер = Прокси.Сервер();
			Порт = Прокси.Порт();
		КонецЕсли;
		
		Журнал.Добавить(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = '%1: %2:%3'"), ВРег(Протокол), Сервер, Формат(Порт, "ЧГ=")));
	Иначе
		Журнал.Добавить(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Адрес:  %1:%2
			           |HTTP:   %3:%4
			           |Secure: %5:%6
			           |FTP:    %7:%8'"),
			Прокси.Сервер(),        Формат(Прокси.Порт(),        "ЧГ="),
			Прокси.Сервер("http"),  Формат(Прокси.Порт("http"),  "ЧГ="),
			Прокси.Сервер("https"), Формат(Прокси.Порт("https"), "ЧГ="),
			Прокси.Сервер("ftp"),   Формат(Прокси.Порт("ftp"),   "ЧГ=")));
	КонецЕсли;
		
	Если Прокси.ИспользоватьАутентификациюОС("") Тогда 
		Журнал.Добавить(НСтр("ru = 'Используется аутентификация операционной системы'"));
	Иначе 
		Пользователь = Прокси.Пользователь("");
		Пароль = Прокси.Пароль("");
		СостояниеПароля = ?(ПустаяСтрока(Пароль), НСтр("ru = '<не указан>'"), НСтр("ru = '********'"));
		
		Журнал.Добавить(НСтр("ru = 'Используется аутентификация по имени пользователя и паролю'"));
		Журнал.Добавить(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Пользователь: %1
			           |Пароль: %2'"),
			Пользователь,
			СостояниеПароля));
	КонецЕсли;
	
	Если Прокси.НеИспользоватьПроксиДляЛокальныхАдресов Тогда 
		Журнал.Добавить(НСтр("ru = 'Не использовать прокси для локальных адресов'"));
	КонецЕсли;
	
	Если Прокси.НеИспользоватьПроксиДляАдресов.Количество() > 0 Тогда 
		Журнал.Добавить(НСтр("ru = 'Не использовать для следующих адресов:'"));
		Для Каждого ИсключаемыйАдрес Из Прокси.НеИспользоватьПроксиДляАдресов Цикл
			Журнал.Добавить(ИсключаемыйАдрес);
		КонецЦикла;
	КонецЕсли;
	
	Возврат СтрСоединить(Журнал, Символы.ПС);
	
КонецФункции

// Возвращает прокси по настройкам НастройкаПроксиСервера для заданного протокола Протокол.
//
// Параметры:
//   НастройкаПроксиСервера - Соответствие из КлючИЗначение:
//    * Ключ - Строка - см. ниже список возможных ключей.
//    * Значение - Произвольный
//    ИспользоватьПрокси - Булево - использовать ли прокси-сервер.
//    НеИспользоватьПроксиДляЛокальныхАдресов - использовать ли прокси-сервер для локальных адресов.
//    НеИспользоватьПроксиДляАдресов - Массив из Строка
//    ИспользоватьСистемныеНастройки - Булево - использовать ли системные настройки прокси-сервера.
//    Сервер       - Строка - адрес прокси-сервера.
//    Порт         - Строка - порт прокси-сервера.
//    Пользователь - Строка - имя пользователя для авторизации на прокси-сервере.
//    Пароль       - Строка - пароль пользователя.
//    ИспользоватьАутентификациюОС - Булево - признак использования аутентификации средствами операционной системы.
//   URLИлиПротокол - Строка - адрес ресурса или протокол, для которого устанавливаются параметры прокси сервера,
//                             например "https://1c.ru", "http", "https", "ftp", "ftps".
//
// Возвращаемое значение:
//   ИнтернетПрокси
//
Функция НовыйИнтернетПрокси(НастройкаПроксиСервера, URLИлиПротокол) Экспорт
	
	Если НастройкаПроксиСервера = Неопределено Тогда
		// Системные установки прокси-сервера.
		Возврат Неопределено;
	КонецЕсли;
	
	ИспользоватьПрокси = НастройкаПроксиСервера.Получить("ИспользоватьПрокси");
	Если Не ИспользоватьПрокси Тогда
		// Не использовать прокси-сервер.
		Возврат Новый ИнтернетПрокси(Ложь);
	КонецЕсли;
	
	ИспользоватьСистемныеНастройки = НастройкаПроксиСервера.Получить("ИспользоватьСистемныеНастройки");
	Если ИспользоватьСистемныеНастройки Тогда
		// Системные настройки прокси-сервера.
		Возврат Новый ИнтернетПрокси(Истина);
	КонецЕсли;
	
	ИспользоватьАутентификациюОС = НастройкаПроксиСервера.Получить("ИспользоватьАутентификациюОС");
	ИспользоватьАутентификациюОС = ?(ИспользоватьАутентификациюОС = Истина, Истина, Ложь);

	ДополнительныеНастройки = НастройкаПроксиСервера.Получить("ДополнительныеНастройкиПрокси");
	Если ТипЗнч(ДополнительныеНастройки) <> Тип("Соответствие") Тогда
		ДополнительныеНастройки = Новый Соответствие;
	КонецЕсли;
	
	// Настройки прокси-сервера, заданные вручную.
	Прокси = Новый ИнтернетПрокси;
	
	Протоколы = СтрРазделить("http,https,ftp,ftps", ",", Ложь);
	Для Каждого Протокол Из Протоколы Цикл
		АдресСервера = НастройкаПроксиСервера["Сервер"];
		Порт = НастройкаПроксиСервера["Порт"];
		
		ПроксиПоПротоколу = ДополнительныеНастройки[Протокол];
		Если ТипЗнч(ПроксиПоПротоколу) = Тип("Структура") Тогда
			АдресСервера = ПроксиПоПротоколу.Адрес;
			Порт = ПроксиПоПротоколу.Порт;
		КонецЕсли;
		
		Если Не ЗначениеЗаполнено(Порт) Тогда
			Порт = Неопределено;
		КонецЕсли;
		
		Прокси.Установить(Протокол, АдресСервера, Порт, 
			НастройкаПроксиСервера["Пользователь"], НастройкаПроксиСервера["Пароль"], ИспользоватьАутентификациюОС);
	КонецЦикла;
	
	Прокси.НеИспользоватьПроксиДляЛокальныхАдресов = НастройкаПроксиСервера["НеИспользоватьПроксиДляЛокальныхАдресов"];
	
	АдресаИсключений = НастройкаПроксиСервера.Получить("НеИспользоватьПроксиДляАдресов");
	Если ТипЗнч(АдресаИсключений) = Тип("Массив") Тогда
		Для каждого АдресИсключения Из АдресаИсключений Цикл
			Прокси.НеИспользоватьПроксиДляАдресов.Добавить(АдресИсключения);
		КонецЦикла;
	КонецЕсли;
	
	Возврат Прокси;
	
КонецФункции

// Записывает событие-ошибку в журнал регистрации с именем "Получение файлов из Интернета".
//
// Параметры:
//   СообщениеОбОшибке - Строка - сообщение об ошибке.
// 
Процедура ЗаписатьОшибкуВЖурналРегистрации(Знач СообщениеОбОшибке)
	
	ЗаписьЖурналаРегистрации(
		СобытиеЖурналаРегистрации(),
		УровеньЖурналаРегистрации.Ошибка, , ,
		СообщениеОбОшибке);
	
КонецПроцедуры

Функция СобытиеЖурналаРегистрации()
	
	Возврат НСтр("ru = 'Получение файлов из Интернета'", ОбщегоНазначения.КодОсновногоЯзыка());
	
КонецФункции

#КонецЕсли

#КонецОбласти

#Область ДиагностикаСоединения

// Служебная информация для отображения текущих настроек и состояний прокси для выполнения диагностики.
//
// Параметры:
//  Протокол - Строка - протокол, для которого необходимо получить настройки прокси.
//
// Возвращаемое значение:
//  Структура:
//     * СоединениеЧерезПрокси - Булево - признак того, что соединение должно выполняться через прокси.
//     * Представление - Строка - представление текущего настроенного прокси.
//
Функция СостояниеНастроекПрокси(Знач Протокол = Неопределено) Экспорт
	
	Протокол = ПротоколДляПрокси(Протокол);
	Прокси = ПолучениеФайловИзИнтернета.ПолучитьПрокси(Протокол);
	НастройкиПрокси = ПолучениеФайловИзИнтернета.НастройкиПроксиНаСервере();
	
	Журнал = Новый Массив;
	
	Если НастройкиПрокси = Неопределено Тогда 
		Журнал.Добавить(НСтр("ru = 'Параметры прокси-сервера в ИБ не указаны (используются системные настройки прокси).'"));
	ИначеЕсли Не НастройкиПрокси.Получить("ИспользоватьПрокси") Тогда
		Журнал.Добавить(НСтр("ru = 'Параметры прокси-сервера в ИБ: Не использовать прокси-сервер.'"));
	ИначеЕсли НастройкиПрокси.Получить("ИспользоватьСистемныеНастройки") Тогда
		Журнал.Добавить(НСтр("ru = 'Параметры прокси-сервера в ИБ: Использовать системные настройки прокси-сервера.'"));
	Иначе
		Журнал.Добавить(НСтр("ru = 'Параметры прокси-сервера в ИБ: Использовать другие настройки прокси-сервера.'"));
	КонецЕсли;
	
	Если Прокси = Неопределено Тогда 
		Прокси = Новый ИнтернетПрокси(Истина);
	КонецЕсли;
	
	СоединениеЧерезПрокси = Не ПустаяСтрока(Прокси.Сервер(Протокол)) Или Не ПустаяСтрока(Прокси.Сервер());
	
	Если СоединениеЧерезПрокси Тогда 
		Журнал.Добавить(НСтр("ru = 'Соединение выполняется через прокси-сервер:'"));
		Журнал.Добавить(ПредставлениеИнтернетПрокси(Прокси, Протокол));
	КонецЕсли;
	
	Результат = Новый Структура;
	Результат.Вставить("СоединениеЧерезПрокси", СоединениеЧерезПрокси);
	Результат.Вставить("Представление", СтрСоединить(Журнал, Символы.ПС));
	Результат.Вставить("ИспользуютсяСистемныеНастройкиПрокси", НастройкиПрокси = Неопределено Или НастройкиПрокси["ИспользоватьСистемныеНастройки"] = Истина);
	
	Возврат Результат;
	
КонецФункции

Функция ПредставлениеМестаДиагностики() Экспорт
	
	Если ОбщегоНазначения.РазделениеВключено() Тогда
		Возврат НСтр("ru = 'Подключение проводится на сервере 1С:Предприятия в интернете (модель сервиса).'");
	Иначе 
		Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда
			Если ОбщегоНазначения.КлиентПодключенЧерезВебСервер() Тогда 
				Возврат СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Подключение проводится из файловой информационной базы на веб-сервере <%1>.'"), ИмяКомпьютера());
			Иначе 
				Возврат СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Подключение проводится из файловой информационной базы на компьютере <%1>.'"), ИмяКомпьютера());
			КонецЕсли;
		Иначе
			Возврат СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Подключение проводится на сервере 1С:Предприятие <%1>.'"), ИмяКомпьютера());
		КонецЕсли;
	КонецЕсли;
	
КонецФункции

Функция ПроверитьДоступностьСервера(АдресСервера) Экспорт
	
	Результат = Новый Структура("Доступен, ЖурналДиагностики", Ложь, "");

	ПараметрыЗапускаПрограммы = ФайловаяСистема.ПараметрыЗапускаПрограммы();
	ПараметрыЗапускаПрограммы.ДождатьсяЗавершения = Истина;
	ПараметрыЗапускаПрограммы.ПолучитьПотокВывода = Истина;
	ПараметрыЗапускаПрограммы.ПолучитьПотокОшибок = Истина;
	ПараметрыЗапускаПрограммы.КодировкаИсполнения = "OEM";
	
	Если ОбщегоНазначения.ЭтоWindowsСервер() Тогда
		ШаблонКоманды = "ping %1 -n 4 -w 1000";
	Иначе
		ШаблонКоманды = "ping -c 4 -W 1 %1";
	КонецЕсли;
	СтрокаКоманды = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонКоманды, АдресСервера);
	
	Попытка
		РезультатЗапуска = ФайловаяСистема.ЗапуститьПрограмму(СтрокаКоманды, ПараметрыЗапускаПрограммы);
	Исключение
		Результат.ЖурналДиагностики = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось проверить доступность интернет-ресурса ""%1"" по причине:
				|%2
				|
				|с помощью команды ""%3"".'"), 
				АдресСервера, ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()), СтрокаКоманды);
		Возврат Результат; 
	КонецПопытки;	
	
	// Разные операционные системы могут выводить ошибки в разные потоки:
	// - для Windows все всегда в потоке вывода;
	// - для Debian или RHEL ошибки падают в поток ошибок.
	ЖурналДоступности = РезультатЗапуска.ПотокВывода + РезультатЗапуска.ПотокОшибок;
	
	Если ОбщегоНазначения.ЭтоWindowsСервер() Тогда
		Доступен = СтрНайти(ЖурналДоступности, "Destination host unreachable") = 0 // Не локализуется.
			И (СтрНайти(ЖурналДоступности, "(0% loss)") > 0 // Не локализуется.
			Или СтрНайти(ЖурналДоступности, "(25% loss)") > 0); // Не локализуется.
	Иначе 
		Доступен = СтрНайти(ЖурналДоступности, "Destination Host Unreachable") = 0 // Не локализуется.
			И (СтрНайти(ЖурналДоступности, "(0% packet loss)") > 0 // Не локализуется.
			Или СтрНайти(ЖурналДоступности, "(25% packet loss)") > 0); // Не локализуется.
	КонецЕсли;
	
	Журнал = Новый Массив;
	Если Доступен Тогда
		Журнал.Добавить(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Удаленный сервер %1 доступен:'"), 
			АдресСервера));
	Иначе
		Журнал.Добавить(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Удаленный сервер %1 не доступен:'"), 
			АдресСервера));
	КонецЕсли;
	
	Журнал.Добавить("> " + СтрокаКоманды);
	Журнал.Добавить(ЖурналДоступности);
	
	Результат.Доступен = Доступен;
	Результат.ЖурналДиагностики = СтрСоединить(Журнал, Символы.ПС);
	Возврат Результат; 
	
КонецФункции

Функция ЖурналТрассировкиМаршрутаСервера(АдресСервера) Экспорт
	
	ПараметрыЗапускаПрограммы = ФайловаяСистема.ПараметрыЗапускаПрограммы();
	ПараметрыЗапускаПрограммы.ДождатьсяЗавершения = Истина;
	ПараметрыЗапускаПрограммы.ПолучитьПотокВывода = Истина;
	ПараметрыЗапускаПрограммы.ПолучитьПотокОшибок = Истина;
	ПараметрыЗапускаПрограммы.КодировкаИсполнения = "OEM";
	
	Если ОбщегоНазначения.ЭтоWindowsСервер() Тогда
		ШаблонКоманды = "tracert -w 100 -h 15 %1";
	Иначе 
		// Если вдруг пакет traceroute не установлен - в потоке вывода будет ошибка.
		// Т.к. результат все равно не разбирается, на поток вывода можно не обращать внимания.
		// По нему администратор поймет что ему надо доставить.
		ШаблонКоманды = "traceroute -w 100 -m 100 %1";
	КонецЕсли;
	
	СтрокаКоманды = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонКоманды, АдресСервера);
	
	Результат = ФайловаяСистема.ЗапуститьПрограмму(СтрокаКоманды, ПараметрыЗапускаПрограммы);
	
	Журнал = Новый Массив;
	Журнал.Добавить(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Трассировка маршрута к удаленному серверу %1:'"), АдресСервера));
	
	Журнал.Добавить("> " + СтрокаКоманды);
	Журнал.Добавить(Результат.ПотокВывода);
	Журнал.Добавить(Результат.ПотокОшибок);
	
	Возврат СтрСоединить(Журнал, Символы.ПС);
	
КонецФункции

Функция ПортПоУмолчанию(Протокол)
	
	ПортыПоУмолчанию = Новый Соответствие;
	ПортыПоУмолчанию.Вставить("http", 80);
	ПортыПоУмолчанию.Вставить("https", 443);
	ПортыПоУмолчанию.Вставить("ftp", 21);
	ПортыПоУмолчанию.Вставить("ftps", 990);
	
	Возврат ПортыПоУмолчанию[НРег(Протокол)];
	
КонецФункции

Функция ПротоколДляПрокси(Знач URLИлиПротокол)
	
	ДопустимыеПротоколы = Новый Соответствие();
	ДопустимыеПротоколы.Вставить("HTTP",  Истина);
	ДопустимыеПротоколы.Вставить("HTTPS", Истина);
	ДопустимыеПротоколы.Вставить("FTP",   Истина);
	ДопустимыеПротоколы.Вставить("FTPS",  Истина);
	
	Если СтрНайти(URLИлиПротокол, "://") > 0 Тогда
		СтруктураURL = ОбщегоНазначенияКлиентСервер.СтруктураURI(URLИлиПротокол);
		Протокол = ?(ПустаяСтрока(СтруктураURL.Схема), "http", СтруктураURL.Схема);
	Иначе
		Протокол = НРег(URLИлиПротокол);
	КонецЕсли;
	
	Если ДопустимыеПротоколы[ВРег(Протокол)] = Неопределено Тогда
		Протокол = "HTTP";
	КонецЕсли;
	
	Возврат Протокол;
	
КонецФункции

#КонецОбласти

#КонецОбласти
